function(warnings_as_errors target)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
      # 5205 : delete of an abstract XXX that has a non-virtual destructor results in undefined behavior (coming from WinRT)
      target_compile_options(${target} PRIVATE /W4 /WX /wd5205)
    elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
      target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic -Werror)
    else()
      # c99-extensions and gnu-zero-variadic-macro-arguments coming from included bgfx headers
      target_compile_options(${target} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-c99-extensions -Wno-gnu-zero-variadic-macro-arguments)
    endif()
endfunction()

function(disable_warnings target)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
      target_compile_options(${target} PRIVATE /W0)
      # Link warning 4264 : archiving object file compiled with /ZW into a static library; note that when authoring Windows Runtime types it is not recommended to link with a static library that contains Windows Runtime metadata unless /WHOLEARCHIVE is specified to include everything from the static library
      set_property(TARGET ${target} PROPERTY STATIC_LIBRARY_OPTIONS /ignore:4264)
    elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
      target_compile_options(${target} PRIVATE -Wno-cpp)
    else()
      target_compile_options(${target} PRIVATE -Wno-everything)
    endif()
endfunction()

# Sets CPU_ARCH and PLATFORM_ARCH variables in the calling scope.
function(set_cpu_platform_arch)
    if(${CMAKE_CXX_COMPILER} MATCHES "x86/cl.exe$")
        set(CPU_ARCH "x86" PARENT_SCOPE)
        set(PLATFORM_ARCH "win" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "x64/cl.exe$")
        set(CPU_ARCH "x64" PARENT_SCOPE)
        set(PLATFORM_ARCH "win" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "arm/cl.exe$")
        set(CPU_ARCH "ARM" PARENT_SCOPE)
        set(PLATFORM_ARCH "win" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "arm64/cl.exe$")
        set(CPU_ARCH "ARM64" PARENT_SCOPE)
        set(PLATFORM_ARCH "win" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "windows-x86_64/bin/clang\\+\\+.exe$")
        set(CPU_ARCH "x64" PARENT_SCOPE)
        set(PLATFORM_ARCH "win" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "linux-x86_64/bin/clang\\+\\+$")
        set(CPU_ARCH "x64" PARENT_SCOPE)
        set(PLATFORM_ARCH "linux" PARENT_SCOPE)
    elseif(${CMAKE_CXX_COMPILER} MATCHES "darwin-x86_64/bin/clang\\+\\+$")
        set(CPU_ARCH "x64" PARENT_SCOPE)
        set(PLATFORM_ARCH "darwin" PARENT_SCOPE)
    else()
        message(FATAL_ERROR "Unrecognized compiler: ${CMAKE_CXX_COMPILER}")
    endif()
endfunction()

# Uses the nuget.config and packages.config files in the current directory to download packages from NuGet.
# NUGET_PATH will be set to the directory where the packages are installed.
function(download_nuget)
    set(NUGET_PATH "${CMAKE_BINARY_DIR}/NuGet")
    set(NUGET_PATH "${NUGET_PATH}" PARENT_SCOPE)
    set(NUGET_EXE "${NUGET_PATH}/nuget.exe")
    if(NOT EXISTS ${NUGET_EXE})
        file(DOWNLOAD "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" ${NUGET_EXE})
    endif()
    file(COPY "nuget.config" DESTINATION ${NUGET_PATH})
    file(COPY "packages.config" DESTINATION ${NUGET_PATH})

    execute_process(COMMAND ${NUGET_EXE} restore WORKING_DIRECTORY ${NUGET_PATH})
    execute_process(COMMAND ${NUGET_EXE} install WORKING_DIRECTORY ${NUGET_PATH})
endfunction()

# Helper for running npm
function(npm)
    cmake_parse_arguments(NPM "" "WORKING_DIRECTORY" "" ${ARGV})

    if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
        set(NPM_COMMAND "npm.cmd")
    else()
        set(NPM_COMMAND "npm")
    endif()

    if (NOT NPM_WORKING_DIRECTORY)
        set(NPM_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
    endif()

    message(STATUS "Installing npm modules (${NPM_WORKING_DIRECTORY})")
    execute_process(COMMAND ${NPM_COMMAND} ${NPM_UNPARSED_ARGUMENTS} WORKING_DIRECTORY ${NPM_WORKING_DIRECTORY} RESULT_VARIABLE NPM_RESULT)
    if(NOT ${NPM_RESULT} EQUAL 0)
        message(FATAL_ERROR "npm command failed: ${NPM_RESULT}")
    else()
        message(STATUS "Installing npm modules (${NPM_WORKING_DIRECTORY}) - done")
    endif()
endfunction()

# Wrapper for FetchContent_MakeAvailable that logs status messages
function(FetchContent_MakeAvailable_With_Message)
    unset(names)

    foreach(name ${ARGV})
        if(NOT ${name}_POPULATED)
            list(APPEND names ${name})
        endif()
    endforeach()

    if(names)
        message(STATUS "Fetching ${names}")
        FetchContent_MakeAvailable(${names})
        message(STATUS "Fetching ${names} - done")
    endif()

    foreach(name ${names})
        string(TOLOWER ${name} name_lowercase)
        set(${name_lowercase}_POPULATED ${${name_lowercase}_POPULATED} PARENT_SCOPE)
        set(${name_lowercase}_SOURCE_DIR ${${name_lowercase}_SOURCE_DIR} PARENT_SCOPE)
        set(${name_lowercase}_BINARY_DIR ${${sname_lowercase}_BINARY_DIR} PARENT_SCOPE)
    endforeach()
endfunction()
